/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package plash.text;

import java.util.ArrayList;
import plash.display.DisplayObjectContainer;
import plash.display.InteractiveObject;
import plash.geom.Point;
import plash.geom.Rectangle;
import plash.utils.ColorMapper;
import processing.core.PApplet;
import processing.core.PFont;
import processing.core.PGraphics;

/**
 *
 * @author #0K Srinivasan <hashok.com>
 */
public class TextField extends InteractiveObject
{

    protected String __text = "";
    protected String __autoSize = TextFieldAutoSize.NONE;
    protected String __restrict;
    protected String __type;
    protected int __borderColor = 0x000000;
    protected int __backgroundColor = 0xFFFFFF;
    protected int __length;
    protected int __maxChars = 0;
    protected int __numlines = 0;
    protected int __textColor = 0x000000;
    protected boolean __border = false;
    protected boolean __background = false;
    protected boolean __displayAsPassword = false;
    protected boolean __multiline = false;
    protected boolean __selectable = true;
    protected boolean __wordWrap = false;
    protected ColorMapper __mapper;
    protected PFont __font;
    protected TextFieldBorder __borderClip = new TextFieldBorder(__borderColor, __backgroundColor);
    protected TextFormat __currentFormat = new TextFormat();
    protected ArrayList<TextFormat> _formats = new ArrayList<TextFormat>();

    public TextField()
    {
        super();
        this.setWidth(200);
        this.setHeight(200);
        _formats.add(new TextFormat());
        __mapper = new ColorMapper(this.__alpha, __currentFormat.getColor());
        __borderClip.setVisible(this.__border || this.__background);
    }

    @Override
    public void draw()
    {        
        int borderHeight;
        int textWidth;
        int textAlign;
        
        if (!__visible)
        {
            return;
        }
        
        if(__parent == null)
        {
            return;
        }
        
        if (__stage == null)
        {
            return;
        }
        if(this.__painter == null)
        {
            return;
        }
        this._updateBoundingBox();
        
        if(__currentFormat.getAlign().equals(TextFieldAutoSize.LEFT) || __currentFormat.getAlign().equals(TextFieldAutoSize.NONE))
        {
            textAlign = PApplet.LEFT;
        }
        else if(__currentFormat.getAlign().equals(TextFieldAutoSize.CENTER))
        {
            textAlign = PApplet.CENTER;
        }
        else
        {
            textAlign = PApplet.RIGHT;
        }
        
        if (this.hasMasker() || this.isMasker())
        {
            this.getPainter().beginDraw();
            this.getPainter().background(0, 0, 0, 0);
        }

        this.getPainter().pushMatrix();
        this.getPainter().translate(this.__x, this.__y);
        this.getPainter().rotate(this.__radiansRotation);
        this.getPainter().scale(__scaleX, __scaleY);

        this.getPainter().textFont(__font);        
        this.getPainter().textAlign(textAlign, PApplet.TOP);

        textWidth = (int) Math.ceil(getPainter().textWidth(__text));
        
        if(__wordWrap)
        {
            if(!__autoSize.equals(TextFieldAutoSize.NONE))
            {
                textWidth = this.getWidth();
            }
            else
            {
                textWidth = Math.min(textWidth, this.getWidth());
                this.setWidth(textWidth);
            }
        }
        textWidth = (textWidth == 0)? 1 : textWidth;
        
        borderHeight = (int) Math.ceil(textWidth / this.getWidth());    
        borderHeight = borderHeight * __currentFormat.getSize();
        borderHeight += (__currentFormat.getLeading() * 3);
        
        this.getPainter().fill(__mapper.getRed(),__mapper.getGreen(), __mapper.getBlue(),__mapper.getAlpha());
        this.getPainter().text(__text, __currentFormat.getLeftMargin(), __currentFormat.getLeading(), textWidth, this.getHeight());
        
        this.__borderClip.setDimensions(
                    new Rectangle(0, 0,
                    textWidth + __currentFormat.getLeftMargin() + __currentFormat.getRightMargin(),
                    borderHeight));
        
        this.setWidth(textWidth);
        this.setHeight(borderHeight);
        
        this.getPainter().popMatrix();
        
        super.draw();
    }

    @Override
    public void setAlpha(float alpha)
    {
        super.setAlpha(alpha);
        __mapper.setAlpha((int) (alpha * 255));
    }

    @Override
    public void setX(int x)
    {
        super.setX(x);
        __borderClip.setX(x);
    }

    @Override
    public void setY(int y)
    {
        super.setY(y);
        __borderClip.setY(y);
    }

    @Override
    public void setScaleX(float scaleX)
    {
        super.setScaleX(scaleX);
        __borderClip.setScaleX(scaleX);
    }

    @Override
    public void setScaleY(float scaleY)
    {
        super.setScaleY(scaleY);
        __borderClip.setScaleY(scaleY);
    }

    @Override
    public void setRotation(int rotation)
    {
        super.setRotation(rotation);
        __borderClip.setRotation(rotation);
    }

    @Override
    public void setPainter(PGraphics painter)
    {
        super.setPainter(painter);
        if (painter != null)
        {
            this.setTextFormat(this.getTextFormat());
        }
    }

    @Override
    public void setParent(DisplayObjectContainer parent)
    {
        super.setParent(parent);

        if (parent == null)
        {
            if (this.__borderClip.getParent() != null)
            {
                this.__borderClip.getParent().removeChild(this.__borderClip);
            }
            return;
        }
        this.setTextFormat(this.getTextFormat());
        try
        {
            parent.addChildAt(this, this.__borderClip);
        }
        catch (Exception e)
        {
        }
    }

    public String getText()
    {
        return __text;
    }

    public void setText(String text)
    {
        this.__text = text;
    }

    public String getAutoSize()
    {
        return __autoSize;
    }

    public void setAutoSize(String autoSize)
    {
        this.__autoSize = autoSize;
    }

    public String getRestrict()
    {
        return __restrict;
    }

    public void setRestrict(String restrict)
    {
        this.__restrict = restrict;
    }

    public String getType()
    {
        return __type;
    }

    public void setType(String type)
    {
        this.__type = type;
    }

    public int getBorderColor()
    {
        return __borderColor;
    }

    public void setBorderColor(int borderColor)
    {
        this.__borderColor = borderColor;
    }

    public int getBackgroundColor()
    {
        return __backgroundColor;
    }

    public void setBackgroundColor(int backgroundColor)
    {
        this.__backgroundColor = backgroundColor;
        this.__borderClip.setBackgroundColor(backgroundColor);
    }

    public int getLength()
    {
        return __length;
    }

    public void setLength(int length)
    {
        this.__length = length;
    }

    public int getMaxChars()
    {
        return __maxChars;
    }

    public void setMaxChars(int maxChars)
    {
        this.__maxChars = maxChars;
    }

    public int getNumlines()
    {
        return __numlines;
    }

    public void setNumlines(int numlines)
    {
        this.__numlines = numlines;
    }

    public int getTextColor()
    {
        return __textColor;
    }

    public void setTextColor(int textColor)
    {
        this.__textColor = textColor;
        this.__currentFormat.setColor(textColor);
        __mapper.setRGB(textColor);
    }

    public boolean hasBorder()
    {
        return __border;
    }

    public void setBorder(boolean border)
    {
        this.__border = border;
        __borderClip.setBorder(border);
        __borderClip.setVisible(this.__border || this.__background);
    }

    public boolean hasBackground()
    {
        return __background;
    }

    public void setBackground(boolean background)
    {
        this.__background = background;
        this.__borderClip.setBackground(background);
        this.__borderClip.setVisible(this.__border || this.__background);
    }

    public boolean isDisplayAsPassword()
    {
        return __displayAsPassword;
    }

    public void setDisplayAsPassword(boolean displayAsPassword)
    {
        this.__displayAsPassword = displayAsPassword;
    }

    public boolean isMultiline()
    {
        return __multiline;
    }

    public void setMultiline(boolean multiline)
    {
        this.__multiline = multiline;
    }

    public boolean isSelectable()
    {
        return __selectable;
    }

    public void setSelectable(boolean selectable)
    {
        this.__selectable = selectable;
    }

    public boolean isWordWrap()
    {
        return __wordWrap;
    }

    public void setWordWrap(boolean wordWrap)
    {
        this.__wordWrap = wordWrap;
    }

    public TextFormat getTextFormat()
    {
        return __currentFormat;
    }

    public void setTextFormat(TextFormat format)
    {
        this.__currentFormat = format;
        if (this.getStage() != null)
        {
            __font = this.getStage().createFont(format.getFont(), format.getSize(), true);
        }
        this.__borderClip.setDimensions(new Rectangle(0, 0, 100, format.getSize()));
    }

    private Rectangle _findRotatedBounds(Rectangle unrotated)
    {
        //the distance between this Display group's registration point and the rectangle's topleft
        int distanceGtoR;
        float fi;
        float theta = this.__radiansRotation;

        Point minPoint = new Point(999999, 999999);
        Point maxPoint = new Point(-999999, -999999);

        ArrayList<Point> rotatedCorners = new ArrayList<Point>();

        distanceGtoR = plash.utils.Math.distance(this.__location, unrotated.getTopLeft());
        fi = (float) java.lang.Math.atan2(
                unrotated.getTopLeft().getY() - __y,
                unrotated.getTopLeft().getX() - __x);

        //rotated Top Left
        rotatedCorners.add(plash.utils.Math.getRotatedLocation(this.__location, distanceGtoR, theta + fi));
        //rotated Top Right
        rotatedCorners.add(plash.utils.Math.getRotatedLocation(rotatedCorners.get(0), unrotated.getWidth(), theta));
        //rotated Bottom Left
        rotatedCorners.add(plash.utils.Math.getRotatedLocation(rotatedCorners.get(0), unrotated.getHeight(), theta + 1.57f));
        //rotated Bottom Right
        rotatedCorners.add(plash.utils.Math.getRotatedLocation(rotatedCorners.get(1),
                unrotated.getHeight(), theta + 1.57f));

        for (Point p : rotatedCorners)
        {
            minPoint.setX(java.lang.Math.min(minPoint.getX(), p.getX()));
            minPoint.setY(java.lang.Math.min(minPoint.getY(), p.getY()));

            maxPoint.setX(java.lang.Math.max(maxPoint.getX(), p.getX()));
            maxPoint.setY(java.lang.Math.max(maxPoint.getY(), p.getY()));
        }
        return new Rectangle(minPoint, new Point(maxPoint.getX() - minPoint.getX(), maxPoint.getY() - minPoint.getY()));
    }

    @Override
    protected void _updateBoundingBox()
    {
        __boundingBox = new Rectangle(0,0,this.getWidth(),this.getHeight());

        __boundingBox.setX(this.getX() + (int) (__boundingBox.getX() * this.__scaleX));
        __boundingBox.setY(this.getY() + (int) (__boundingBox.getY() * this.__scaleY));

        __boundingBox.setWidth((int) (this.__scaleX * __boundingBox.getWidth()));
        __boundingBox.setHeight((int) (this.__scaleY * __boundingBox.getHeight()));

        if (this.__rotation != 0)
        {
            Rectangle newBounds = _findRotatedBounds(__boundingBox);
            __boundingBox = newBounds;
        }
        try
        {
            __boundingBox.setX(__boundingBox.getX() + getParent().getAbsoluteX());
            __boundingBox.setY(__boundingBox.getY() + getParent().getAbsoluteY());
        }
        catch(NullPointerException npe)
        {
            
        }
    }

    @Override
    public Rectangle getBoundingBox()
    {
        _updateBoundingBox();
        return __boundingBox;
    }

    @Override
    public void setVisible(boolean visible)
    {
        super.setVisible(visible);
        __borderClip.setVisible(visible);
    }

    /**
     * Start of the TextFieldBorder class;
     */
    class TextFieldBorder extends DisplayObjectContainer
    {
        private boolean _border = false;
        private boolean _background = false;
        
        private int _borderColor = 0x000000;
        private int _backgroundColor = 0xFFFFFF;
        private Rectangle _dimensions = new Rectangle(0, 0, 50, 50);

        public TextFieldBorder(int borderColor, int backgroundColor)
        {
            super();
            _borderColor = borderColor;
            _backgroundColor = backgroundColor;
            _update();
        }

        private void _update()
        {
            this.getGraphics().clear();
            if(this._border)
            {
                this.getGraphics().setLineStyle(7, 0x000000, 1.0f);

                this.getGraphics().drawRectangle(_dimensions);

                this.getGraphics().setLineStyle(4, 0xFFFFFF, 1.0f);
                this.getGraphics().drawRectangle(_dimensions);

                this.getGraphics().setLineStyle(1, 0xCCCCCC, 1.0f);
            }
            if(this._background)
            {
                this.getGraphics().beginFill(_backgroundColor, __alpha);
                this.getGraphics().drawRectangle(_dimensions);
                this.getGraphics().endFill();
            }
        }

        public int getBorderColor()
        {
            return _borderColor;
        }

        public void setBorderColor(int borderColor)
        {
            this._borderColor = borderColor;
            _update();
        }

        public int getBackgroundColor()
        {
            return _backgroundColor;
        }

        public void setBackgroundColor(int backgroundColor)
        {
            this._backgroundColor = backgroundColor;
            _update();
        }

        public Rectangle getDimensions()
        {
            return _dimensions;
        }

        public void setDimensions(Rectangle dimensions)
        {
            this._dimensions = dimensions;
            _update();
        }

        public boolean isBorder()
        {
            return _border;
        }

        public void setBorder(boolean _border)
        {
            this._border = _border;
            _update();
        }

        public boolean isBackground()
        {
            return _background;
        }

        public void setBackground(boolean _background)
        {
            this._background = _background;
            _update();
        }        
    }
}